//! System call return value handling
//! SPDX-License-Identifier: MPL-2.0

const std = @import("std");
const SyscallError = @import("error.zig").SyscallError;

/// System call return value
pub const SyscallReturn = union(enum) {
    /// Successful return with value
    return_value: u64,
    
    /// Error return with error code
    error_code: SyscallError,
    
    /// Restart the system call
    restart_syscall: void,
    
    /// Signal delivery required
    signal: struct {
        signal_num: u32,
        return_value: u64,
    },
    
    const Self = @This();
    
    /// Create a successful return
    pub fn success(value: u64) Self {
        return Self{ .return_value = value };
    }
    
    /// Create an error return
    pub fn error_return(err: SyscallError) Self {
        return Self{ .error_code = err };
    }
    
    /// Create a restart return
    pub fn restart() Self {
        return Self{ .restart_syscall = {} };
    }
    
    /// Create a signal return
    pub fn signal_return(signal_num: u32, value: u64) Self {
        return Self{ .signal = .{ .signal_num = signal_num, .return_value = value } };
    }
    
    /// Check if this is an error
    pub fn is_error(self: Self) bool {
        return switch (self) {
            .error_code => true,
            else => false,
        };
    }
    
    /// Check if this is a success
    pub fn is_success(self: Self) bool {
        return switch (self) {
            .return_value => true,
            else => false,
        };
    }
    
    /// Check if this should restart
    pub fn should_restart(self: Self) bool {
        return switch (self) {
            .restart_syscall => true,
            .error_code => |err| err.is_restartable(),
            else => false,
        };
    }
    
    /// Convert to raw return value (for ABI compatibility)
    pub fn to_raw(self: Self) u64 {
        return switch (self) {
            .return_value => |val| val,
            .error_code => |err| @bitCast(@as(i64, err.to_return_value())),
            .restart_syscall => @bitCast(@as(i64, SyscallError.ERESTARTSYS.to_return_value())),
            .signal => |sig| sig.return_value,
        };
    }
    
    /// Convert from raw return value
    pub fn from_raw(raw: u64) Self {
        const signed: i64 = @bitCast(raw);
        if (signed >= 0) {
            return Self{ .return_value = raw };
        } else {
            const error_code: SyscallError = @enumFromInt(-signed);
            return Self{ .error_code = error_code };
        }
    }
    
    /// Get the actual return value (0 for errors)
    pub fn get_value(self: Self) u64 {
        return switch (self) {
            .return_value => |val| val,
            .signal => |sig| sig.return_value,
            else => 0,
        };
    }
    
    /// Get the error code (SUCCESS if not an error)
    pub fn get_error(self: Self) SyscallError {
        return switch (self) {
            .error_code => |err| err,
            .restart_syscall => SyscallError.ERESTARTSYS,
            else => SyscallError.SUCCESS,
        };
    }
    
    /// Map the return value if successful
    pub fn map(self: Self, comptime func: fn(u64) u64) Self {
        return switch (self) {
            .return_value => |val| Self{ .return_value = func(val) },
            else => self,
        };
    }
    
    /// Map error if present
    pub fn map_error(self: Self, comptime func: fn(SyscallError) SyscallError) Self {
        return switch (self) {
            .error_code => |err| Self{ .error_code = func(err) },
            else => self,
        };
    }
};